#include "debug.hpp"

#include "instructions.hpp"

#include <iostream>
using std::endl;
using std::flush;


namespace ast {


DebugVisitor::DebugVisitor(ostream& os) : out(os)
{ }


void DebugVisitor::visit(DataSection& sec)
{
  out << "\n.data";
}


void DebugVisitor::visit(Directive& d)
{
  out << "\n\t";

  for (uint i = 0; i < d.labels->size(); ++i) {
    out << *(d.labels->at(i)) << ": ";
  }

  switch (d.dirType) {
    case Tascii:
      out << ".ascii \"" << *(d.arg.str) << "\""; break;

    case Tasciiz:
      out << ".asciiz \"" << *(d.arg.str) << "\""; break;

    case Tresw:
      out << ".resw " << d.arg.size; break;
/*
    case Tstart:
      out << ".start " << *(d.arg.str); break;

    case Tglobal:
      out << ".global " << *(d.arg.str); break;

    case Textern:
      out << ".extern " << *(d.arg.str); break;
*/
    case Tword:
      out << ".word ";

      for (uint i = 0; i < d.arg.intList->size(); ++i) {
        if (i) out << ", ";
        out << d.arg.intList->at(i);
      }

      break;

    default:
      break;
  }
}


void DebugVisitor::visit(TextSection& sec)
{
  out << "\n.text";
}


void DebugVisitor::visit(Instruction& instr)
{
  out << '\n';

  for (uint i = 0; i < instr.labels->size(); ++i) {
    if (i) out << '\n';
    out << *(instr.labels->at(i)) << ": ";
  } 

  if (!instr.labels->empty()) out << '\n';

  out << '\t' << risco::instruction_str(instr.opcode);

  if (instr.apsBit) out << '!';

  out << "[" << instr.operand_format << "]";
}


void DebugVisitor::visit(Operand& operand)
{
  out << ' ';

  switch (operand.type) {
    case ast::Operand::Register:
    case ast::Operand::ZeroRegister:
      out << 'r' << operand.arg.value;
      break;

    case ast::Operand::ConstantP:
      out << operand.arg.value << 'P';
      break;

    case ast::Operand::ConstantL:
      out << operand.arg.value << 'L';
      break;

    case ast::Operand::ConstantH:
      out << operand.arg.value << 'H';
      break;

    case ast::Operand::LabelC:
      out << *operand.arg.str;
      break;

    case ast::Operand::LabelH:
      out << '@' << *operand.arg.str;

    default:
      break;
  }
}


}
